package core

import (
	"context"
	"cyiris/core/http"
	"cyiris/core/mq"
	"cyiris/core/mysql"
	"cyiris/core/zaplog"
	log "cyiris/core/zaplog"
	"fmt"
	"time"

	"cyiris/core/config"

	"github.com/go-redis/redis/v8"
	"gorm.io/gorm"
)

var (
	err         error
	cfg         *config.Config
	httpServer  http.HttpServer
	dbs         map[string]*gorm.DB
	redisClient map[string]*redis.Client
	task        *mq.Task
	mqPublisher map[string]*mq.Publisher
)

func GetMqPublisher(exchangeName string) (*mq.Publisher, error) {
	pub, ok := mqPublisher[exchangeName]
	if !ok {
		log.Errorf("Publisher<%s> not exixts ", exchangeName)
		return nil, fmt.Errorf("Publisher<%s> not exixts ", exchangeName)
	}

	return pub, nil
}

func setupMqPublisher() {
	conns := make(map[string]*mq.Connector)
	mqPublisher = make(map[string]*mq.Publisher)

	for name, addr := range cfg.MqCfg {
		conns[name] = mq.NewConnector(name, addr)
	}

	for _, v := range cfg.ExchangeCfg {
		conn, ok := conns[v.MqName]
		if !ok {
			log.Errorf("Connector<%s> not exixts ", v.MqName)
			continue
		}

		mqPublisher[v.ExchangeName] = mq.NewPublisher(conn, v.ExchangeName, v.ExchangeType)
	}
}

func setupTask() {
	task = mq.NewTask(cfg.MqCfg, cfg.QuereCfg)
}

func GetTask() *mq.Task {
	return task
}

/**
 * 注册mq任务
 */
func RegisterTask(serviceName string, ctrl mq.Ctrl) {
	task.RegisterRouter(serviceName, ctrl)
}

/**
 * 初始化 http 服务器
 */
func setupHttpServer() {
	httpServer = http.NewHttpServer(cfg.ServerHost)
}

func GetHttpServer() http.HttpServer {
	return httpServer
}

/**
 * 初始化 redis
 */
func setupRedis() {
	redisClient = make(map[string]*redis.Client)

	for name, config := range cfg.Redis {
		redisClient[name] = redis.NewClient(&redis.Options{
			Addr:     config.Addr,
			Password: config.Passwd,
			DB:       config.Db,
			PoolSize: config.PoolSize,
		})

		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
		defer cancel()

		_, err := redisClient[name].Ping(ctx).Result()
		if err != nil {
			log.Errorf("setup redis error: %v", err)
			panic(fmt.Sprintf("setup redis error: %v", err))
		}
	}
}

func GetRedis(name string) (rds *redis.Client, err error) {
	var ok bool

	if rds, ok = redisClient[name]; ok {
		return rds, nil
	}

	log.Errorf("redis: %s not found", name)
	return nil, fmt.Errorf("redis: %s not found", name)
}

/**
 * 初始化数据库
 */
func setupMysqlDb() {
	dbs = make(map[string]*gorm.DB)

	for name, config := range cfg.Mysql {
		db, err := mysql.NewDB(config)

		if nil != err {
			log.Errorf("setup mysql db error: %v", err)
			panic(fmt.Sprintf("setup mysql db error: %v", err))
		}

		dbs[name] = db
	}
}

/**
 * 获取数据库链接
 */
func GetMysqlDb(name string) (db *gorm.DB, err error) {
	var ok bool

	if db, ok = dbs[name]; ok {
		return db, nil
	}

	log.Errorf("db: %s not found", name)
	return nil, fmt.Errorf("db: %s not found", name)
}

/**
 * 注册路由
 */
func RegisterRouter(method, uri string, ctrl http.Ctrl) {
	httpServer.RegisterRouter(method, uri, ctrl)
}

/**
 * 服务初始化
 */
func InitServer() {
	// 载入系统配置
	cfg, err = config.NewConfig()
	if nil != err {
		panic(fmt.Sprintf("init config error: %v", err))
	}

	// 初始化日志
	zaplog.SetupLog(cfg.LogConfig)

	log.Debugf("config: %#v", cfg)

	//
	setupMysqlDb()

	setupRedis()
	setupTask()
	setupMqPublisher()

	setupHttpServer()
}

func Run() {
	log.Debugf("server start at %s", cfg.ServerHost)
	httpServer.Start()
}
